
/*							*/
/*  Indexed Sequential Access Method			*/
/*  Relational Database Systems, Inc.			*/
/*							*/
/*		Proprietary Data			*/
/*    This document contains proprietary information	*/
/* and trade secrets which are the property of		*/
/* Relational Database Systems, Inc. (RDSI). This	*/
/* document is submitted to recipient in confidence.	*/
/* The information contained herein may not be used,	*/
/* copied or disclosed in whole or in part except as	*/
/* permitted by written agreement signed by an officer	*/
/* of RDSI.						*/
/*							*/

/*
 * isam create and delete routines
 *
 * Relational Database Systems, Inc.
 * Roy Harrington	November 4, 1981
 *
 *  06-07-83 RVH  V104 -- added kernel modifications
 *  10-13-83 RVH  V201 -- prevent deletion of current key
 */

#include "isdec.c"

/*
 * build isam file
 */

isbuild(filename, reclength, keydesc, mode)
char *filename;		/* V104 NOTE: for kernel this is array of ptrs */
int reclength;
register struct keydesc *keydesc;
register int mode;
{
	register int lockmode;
	register struct buff *bp;
	int isfd;
#ifndef ISKERNEL
	char fname[PATHSIZE];
#endif  /* ISKERNEL */

	iserrno = iserrio = 0;

	if (reclength <= 0 || reclength > RECORDSIZE)
	    {
	    iserrno = EBADARG;
	    return(-1);
	    }

#ifndef ISKERNEL	/* V104 */
	if (ckfilname(filename)) return(-1);
#endif

	if (kylegal(keydesc, reclength) != 0)
	    return(-1);

	if ((isfd = allocopen()) < 0)
	    return(-1);

	openp->o_mode = mode;
	lockmode = mode & LOCKMASK;
	mode &= IOMASK;
	switch(lockmode)
	    {
	    case OLD_AUTO:
		lockmode = ISAUTOLOCK; break;
	    case OLD_EXCL:
		lockmode = ISEXCLLOCK; break;
	    case ISAUTOLOCK:
	    case ISMANULOCK:
	    case ISEXCLLOCK:
		break;
	    default:
		iserrno = EBADARG;
		goto createrr;
	    }
	switch(mode)
	    {
	    case ISINPUT:
	    case ISOUTPUT:
	    case ISINOUT:
		break;
	    default:
		iserrno = EBADARG;
		goto createrr;
	    }

#ifndef ISKERNEL	/* V104 */
	mkidxname(filename, fname);		/* make filename.idx	*/
	if (makefile(fname) == -1)		/* create index file	*/
	    {
	    iserrio = IO_CREA+IO_IDX;
	    goto createrr;
	    }

	mkdatname(filename, fname);		/* make filename.dat	*/
	if (makefile(fname) == -1)		/* create data file	*/
	    {
	    iserrio = IO_CREA+IO_DAT;
	    goto createrr;
	    }

#ifdef CREATLOCK
	mklokname(filename, fname);		/* make filename.lok	*/
	if (makefile(fname) == -1)		/* create lock file	*/
	    {
	    iserrio = IO_CREA+IO_LOK;
	    goto createrr;
	    }
#endif /* CREATLOCK */
#endif /* ISKERNEL  */
						/* setup fileid		*/
	filep = openp->o_filep = allocfile(filename, mode);
	if (filep == NULL)
	    goto createrr;

	if (lksemaphore(LOCKUNCOND) || lkopenlock(lockmode))
	    goto createrr;

	filep->f_idxsize = NODESIZE-1;
	filep->f_datsize = reclength;
#ifdef MPM86
	filep->f_datsize |= 0177;		/* make 128 byte records*/
#endif /* MPM86 */

	filep->f_dicbp = bfgetclr(1L);		/* get dictionary block	*/
	dictp = filep->f_dicbp->bf_un.bf_dict;

	st2(ISMAGIC,	dictp->d_magic);	/* init dictionary	*/
	st1(2,		dictp->d_dummy1+0);
	st1(2,		dictp->d_dummy1+1);
	st1(4,		dictp->d_dummy1+2);
	st1(4,		dictp->d_dummy1+3);
	st2(NODESIZE-1,	dictp->d_idxsize);
	st2(0,		dictp->d_nkeys);
	st1(COMPRESS>>1,dictp->d_cflag);
	st1(2,		dictp->d_dflag);
	st2(reclength,	dictp->d_recsize);
	st4(1L,		dictp->d_uniqid);
	st4(2L,		dictp->d_keysnode);
	st4(2L,		dictp->d_nextnode);

	filep->f_dicbp->bf_flags |= BFMODF|BFDONE;

	bp = bfgetclr(2L);			/* get keys node blcok	*/
	bp->bf_used = 6;			/* init used bytes	*/
	bp->bf_level = 0x7E;
	bp->bf_type = 0xFF;
	bfdwrite(bp);

	if (kyadd(keydesc) != 0)
	    iserrno = EBADKEY;

	kycopy(keydesc, &openp->o_curkey);	/* make it current key	*/

	if (iserrno == 0)
	    {
	    VOID isexit();
	    return(isfd);			/* return is file desc	*/
	    }

	VOID lkopenlock(UNLOCK);
	VOID isexit();

createrr:
	if (openp->o_flags & OSLOCK)		/* semaphore lock on ?	*/
	    VOID lksemaphore(UNLOCK);		/* yes, release it	*/
	freeopen(openp);			/* free tables		*/
	return(-1);				/* return error	code	*/
}


/*
 * add an index to ISAM file
 */

isaddindex(isfd, keydesc)
int isfd;
register struct keydesc *keydesc;
{
	struct item item;
	long recnum, lastnum;

	if (isenter(isfd, ISINOUT) == -1)	/* initialize		*/
	    return(-1);
	
	if (! (openp->o_mode & ISEXCLLOCK))
	    {
	    iserrno = ENOTEXCL;
	    return(isexit());
	    }

	if (kylegal(keydesc, filep->f_datsize) != 0)
	    goto bad;
	
	if (keydesc->k_flags & ~(ld1(dictp->d_cflag)<<1) & COMPRESS)
	    goto bad;				/* compression ok ?	*/

	if (kyadd(keydesc) != 0)
	    goto bad;
	
	lastnum = ld4(dictp->d_nextdata);	/* last record written	*/
	for (recnum = 1L; recnum <= lastnum && iserrno == 0; recnum++)
	    {
	    if (dataread(temprecord, recnum) < 0)  /* read record	*/
		continue;			/* skip this record	*/
	    itmake(temprecord, &item, keydesc);
	    item.it_ptr = recnum;
	    VOID btadditem(&item, keydesc);
	    }

	if (iserrno != 0)
	    {					/* unable to add index	*/
	    btrecover(keydesc->k_rootnode, keydesc);
	    VOID kydelete(keydesc);		/* delete the key	*/
	    }
	return(isexit());

bad:
	if (iserrno == 0) iserrno = EBADKEY;
	return(isexit());
}

/*
 * delete an index from ISAM file
 */

isdelindex(isfd, keydesc)
int isfd;
register struct keydesc *keydesc;
{
	if (isenter(isfd, ISINOUT) == -1)	/* initialize		*/
	    return(-1);
/*
 * check for key exists and not primary key
 */
	if (! (openp->o_mode & ISEXCLLOCK))
	    {
	    iserrno = ENOTEXCL;
	    goto bad;
	    }

	if (kysearch(keydesc, 0) == 1)		/* check for primary key */
	    {
	    iserrno = EPRIMKEY;
	    goto bad;
	    }

	if (kycompare(keydesc, &openp->o_curkey) == 0)  /* V201 */
	    {					/* check for current key */
	    iserrno = EBADKEY;
	    goto bad;
	    }
	
	if (kydelete(keydesc) != 0)		/* delete the key desc	*/
	    {
	    iserrno = EBADKEY;
	    goto bad;
	    }
	
	btrecover(keydesc->k_rootnode, keydesc);/* recover btree nodes	*/

bad:
	return(isexit());
}

#ifndef ISKERNEL	/* V104 iserase, isrename, isremlock not in kernel */
/*
 * erase ISAM file
 */

iserase(filename)
register char *filename;
{
	char fname[PATHSIZE];

	iserrno = iserrio = 0;

	if (ckfilname(filename)) return(-1);

	mkidxname(filename, fname);		/* remove filename.idx	*/
	if (unlink(fname)) iserrno = errno;

	mkdatname(filename, fname);		/* remove filename.dat	*/
	if (unlink(fname)) iserrno = errno;

#ifdef CREATLOCK
	mklokname(filename, fname);		/* remove filename.lok	*/
	if (unlink(fname)) iserrno = errno;
#endif
						/* remove audit trail	*/
	return(iserrno ? -1 : 0);
}

/*
 * remove ISAM lock files
 */

isremlock(filename)
register char *filename;
{
#ifdef CREATLOCK
	char fname[PATHSIZE];
	register int fd;
	/*new fileid*/
	dev_t filedev;
	ino_t fileino;


	iserrno = iserrio = 0;
	if (ckfilname(filename)) return(-1);

	mklokname(filename, fname);		/* trunc filename.lok	*/
	if ((fd = creat(fname, CREATMODE)) == -1)
	    {
	    iserrno = errno;
	    iserrio = IO_CREA+IO_LOK;
	    return(-1);
	    }
	VOID close(fd);

	mkidxname(filename, fname);
	getfileid(fname, &filedev, &fileino);
	mksemname(filedev, fileino, fname);
	VOID unlink(fname);
#else
	iserrno = iserrio = 0;
	if (ckfilname(filename)) return(-1);
#endif
	return(0);
}

/*
 * rename ISAM file
 */

#ifndef MPM86
#ifndef PCDOS
#define rename(o,n)	(link(o,n)||unlink(o))
#endif
#endif

isrename(oldfilename, newfilename)
register char *oldfilename;
register char *newfilename;
{
	char oldfname[PATHSIZE];
	char newfname[PATHSIZE];

	iserrno = iserrio = 0;

	if (ckfilname(oldfilename)) return(-1);
	if (ckfilname(newfilename)) return(-1);

	mkidxname(oldfilename, oldfname);	/* rename filename.idx	*/
	mkidxname(newfilename, newfname);
	if (rename(oldfname, newfname)) goto bad;

	mkdatname(oldfilename, oldfname);	/* rename filename.dat	*/
	mkdatname(newfilename, newfname);
	if (rename(oldfname, newfname)) goto bad;

#ifdef CREATLOCK
	mklokname(oldfilename, oldfname);	/* rename filename.lok	*/
	mklokname(newfilename, newfname);
	if (rename(oldfname, newfname)) goto bad;
#endif
	return(0);
bad:
	iserrno = errno;
	return(-1);
}
#endif /* ISKERNEL */

/*
 * recover btree nodes from deleted index
 */

STATIC int btrecover(node, keydesc)
long node;
register struct keydesc *keydesc;
{
	struct item tmpitem;
	register struct item *ip;
	register int offset, used;
	register struct buff *bp;
	register char *np;

	if (node == 0) return;			/* down to bottom ?	*/

	bp = bfread(node);
	if (bp == NULL) return;
	np = bp->bf_un.bf_node->n_items;
	ip = &tmpitem;
	if (bp->bf_level != 0)			/* not a leaf node ?	*/
	    {
	    used = bp->bf_used - 2;
	    for (offset = 0; offset < used; )
		{
		offset = itunpack(np, offset, ip, keydesc);
		btrecover(ip->it_ptr, keydesc);
		}
	    }
	bfrelease(bp);
	freerec(node, INDXREC);			/* free index record	*/
}

